using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using EntLibContrib.PolicyInjection.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;
using System.Reflection;
using System.Threading;
using System.ComponentModel;

namespace EntLibContrib.PolicyInjection.CallHandlers
{
    /// <summary>
    /// An <see cref="ICallHandler"/> that uses ISynchronizeInvoke to invoke the next handler.
    /// </summary>
    /// <remarks>Only supported for targets implementing ISynchronizeInvoke. Otherwise, the handler will have no effect.</remarks>
    [ConfigurationElementType(typeof(SynchronizedCallHandlerData))]
    public class SynchronizedCallHandler : ICallHandler
    {
        #region ICallHandler Members

        /// <summary>
        /// Processes the method call.
        /// </summary>
        /// <remarks>This handler invokes the call using ISynchronizeInvoke</remarks>
        /// <param name="input"><see cref="IMethodInvocation"/> with information about the call.</param>
        /// <param name="getNext">delegate to call to get the next handler in the pipeline.</param>
        /// <returns>Return value from the target.</returns>
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            IMethodReturn result = null;

            ISynchronizeInvoke synchronizedInvoke = input.Target as ISynchronizeInvoke;

            if (synchronizedInvoke == null ||
                !synchronizedInvoke.InvokeRequired)
            {
                result = getNext()(input, getNext);
            }
            else
            {
                synchronizedInvoke.Invoke(new ThreadStart(delegate()
                {
                    result = getNext()(input, getNext);
                }), null);
            }

            return result;
        }

        #endregion
    }
}
